/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package cz.muni.fi.heathrow.servicesImpl;

import cz.muni.fi.heathrow.dao.AircraftDAO;
import cz.muni.fi.heathrow.dao.DestinationDAO;
import cz.muni.fi.heathrow.dao.FlightDAO;
import cz.muni.fi.heathrow.dao.StewardDAO;
import cz.muni.fi.heathrow.dto.DTOAssembler;
import cz.muni.fi.heathrow.entities.Aircraft;
import cz.muni.fi.heathrow.entities.Destination;
import cz.muni.fi.heathrow.entities.Flight;
import cz.muni.fi.heathrow.entities.Steward;
import cz.muni.fi.heathrowapi.FlightService;
import cz.muni.fi.heathrowapi.dto.DestinationDTO;
import cz.muni.fi.heathrowapi.dto.FlightDTO;
import cz.muni.fi.heathrowapi.dto.StewardDTO;
import cz.muni.fi.heathrowapi.HeathrowRoles;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

/**
 *
 * @author Ufonzak
 */
@Service
public class FlightServiceImpl implements FlightService
{

    private DestinationDAO destinationDao;
    private StewardDAO stewardDao;
    private AircraftDAO aircraftDao;
    private FlightDAO flightDao;

    public DestinationDAO getDestinationDao()
    {
        return destinationDao;
    }

    public FlightDAO getFlightDao()
    {
        return flightDao;
    }

    public StewardDAO getStewardDao()
    {
        return stewardDao;
    }

    public AircraftDAO getAircraftDao()
    {
        return aircraftDao;
    }

    public void setAircraftDao(AircraftDAO aircraftDao)
    {
        this.aircraftDao = aircraftDao;
    }

    public void setDestinationDao(DestinationDAO destinationDao)
    {
        this.destinationDao = destinationDao;
    }

    public void setFlightDao(FlightDAO flightDao)
    {
        this.flightDao = flightDao;
    }

    public void setStewardDao(StewardDAO stewardDao)
    {
        this.stewardDao = stewardDao;
    }

    public FlightServiceImpl()
    {
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED)
    @PreAuthorize("hasRole('" + HeathrowRoles.ADMIN + "')")
    public void create(FlightDTO flight)
    {
        Flight fl = new Flight();
        DTOAssembler.UpdateFlightDomainObject(flight, fl);
        updateRelations(flight, fl);

        flightDao.create(fl);
        DTOAssembler.UpdateFlightDTO(flight, fl);
    }

    private void updateRelations(FlightDTO flight, Flight fl)
    {
        if (flight.getAircraft() != null)
        {
            Aircraft a = aircraftDao.get(flight.getAircraft().getId());
            if (a == null)
                throw new NullPointerException("Cannot find airplane");
            fl.setAircraft(a);
        } else
            fl.setAircraft(null);

        if (flight.getFlightFrom() != null)
        {
            Destination d = destinationDao.getDestination(flight.getFlightFrom().getId());
            if (d == null)
                throw new NullPointerException("Cannot destiantion from");
            fl.setFlightFrom(d);
        } else
            fl.setFlightFrom(null);

        if (flight.getFlightTo() != null)
        {
            Destination d = destinationDao.getDestination(flight.getFlightTo().getId());
            if (d == null)
                throw new NullPointerException("Cannot destiantion to");
            fl.setFlightTo(d);
        } else
            fl.setFlightTo(null);

        List<Steward> stewards = new ArrayList<>();
        if (flight.getStewards() != null)
            for (StewardDTO stew : flight.getStewards())
            {
                Steward s = stewardDao.get(stew.getId());
                if (s == null)
                    throw new NullPointerException("Cannot find steward " + s.getId());
                stewards.add(s);
            }
        fl.setStewards(stewards);
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED, readOnly = true)
    @PreAuthorize("hasRole('" + HeathrowRoles.USER + "')")
    public FlightDTO get(Long id)
    {
        return DTOAssembler.CreateFlightDTO(flightDao.get(id));
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED)
    @PreAuthorize("hasRole('" + HeathrowRoles.ADMIN + "')")
    public void update(FlightDTO flight)
    {
        Flight fl = flightDao.get(flight.getId());
        if (fl == null)
            throw new NullPointerException("Cannot find flight " + flight.toString());
        DTOAssembler.UpdateFlightDomainObject(flight, fl);
        updateRelations(flight, fl);

        flightDao.update(fl);
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED)
    @PreAuthorize("hasRole('" + HeathrowRoles.ADMIN + "')")
    public void remove(FlightDTO flight)
    {
        flightDao.remove(flightDao.get(flight.getId()));
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED, readOnly = true)
    @PreAuthorize("hasRole('" + HeathrowRoles.USER + "')")
    public List<FlightDTO> findAll()
    {
        return new ArrayList<>(CollectionUtils.collect(flightDao.findAll(), DTOAssembler.gegFlightCollectionTransorm()));
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED, readOnly = true)
    @PreAuthorize("hasRole('" + HeathrowRoles.USER + "')")
    public List<FlightDTO> findByTakeoff(Calendar from, Calendar till)
    {
        return new ArrayList<>(CollectionUtils.collect(flightDao.findByTakeoff(from, till), DTOAssembler.gegFlightCollectionTransorm()));
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED, readOnly = true)    
    @PreAuthorize("hasRole('" + HeathrowRoles.USER + "')")
    public List<FlightDTO> findByDestination(DestinationDTO destination)
    {
        return new ArrayList<>(CollectionUtils.collect(flightDao.findByDestination(destinationDao.getDestination(destination.getId())), DTOAssembler.gegFlightCollectionTransorm()));

    }
}
